package com.guardchina.framework.util.utils;

import org.apache.commons.lang3.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 描述：校验工具类
 *
 * @author lwb
 * @date 2019/5/24 11:56
 */
public class CheckUtil {

    /**
     * 校验身份证
     * @param cardNo 身份证号码
     * @return true 是 false 否
     */
    public static boolean isBankCard(String cardNo){
        if(StringUtils.isBlank(cardNo)){
            return false;
        }

        int minLength = 15;

        int maxLength = 19;

        if(cardNo.length() < minLength || cardNo.length() > maxLength) {
            return false;
        }
        char checkFail = 'N';
        char bit = getBankCardCheckCode(cardNo.substring(0, cardNo.length() - 1));
        if(bit == checkFail){
            return false;
        }
        return cardNo.charAt(cardNo.length() - 1) == bit;
    }

    public static boolean isName(String name){
        if(StringUtils.isBlank(name)){
            return false;
        }

        Pattern pattern = Pattern.compile(ValidationUtils.REGEX_ZH_NAME);

        Matcher matcher = pattern.matcher(name);

        return matcher.matches();
    }

    /**
     * 校验身份证
     * @param idNumber 身份证号码
     * @return true 是 false 否
     */
    public static boolean isIdNum(String idNumber) {
        if (idNumber == null || "".equals(idNumber)) {
            return false;
        }
        // 定义判别用户身份证号的正则表达式（15位或者18位，最后一位可以为字母）
        String regularExpression = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
                "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
        //假设18位身份证号码:41000119910101123X  410001 19910101 123X
        //^开头
        //[1-9] 第一位1-9中的一个      4
        //\\d{5} 五位数字           10001（前六位省市县地区）
        //(18|19|20)                19（现阶段可能取值范围18xx-20xx年）
        //\\d{2}                    91（年份）
        //((0[1-9])|(10|11|12))     01（月份）
        //(([0-2][1-9])|10|20|30|31)01（日期）
        //\\d{3} 三位数字            123（第十七位奇数代表男，偶数代表女）
        //[0-9Xx] 0123456789Xx其中的一个 X（第十八位为校验值）
        //$结尾

        //假设15位身份证号码:410001910101123  410001 910101 123
        //^开头
        //[1-9] 第一位1-9中的一个      4
        //\\d{5} 五位数字           10001（前六位省市县地区）
        //\\d{2}                    91（年份）
        //((0[1-9])|(10|11|12))     01（月份）
        //(([0-2][1-9])|10|20|30|31)01（日期）
        //\\d{3} 三位数字            123（第十五位奇数代表男，偶数代表女），15位身份证不含X
        //$结尾


        boolean matches = idNumber.matches(regularExpression);

        int newIdNumLength = 18;
        //判断第18位校验值
        if (matches) {
            if (idNumber.length() == newIdNumLength) {
                char[] charArray = idNumber.toCharArray();
                //前十七位加权因子
                int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
                //这是除以11后，可能产生的11位余数对应的验证码
                String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
                int sum = 0;
                for (int i = 0; i < idCardWi.length; i++) {
                    int current = Integer.parseInt(String.valueOf(charArray[i]));
                    int count = current * idCardWi[i];
                    sum += count;
                }
                char idCardLast = charArray[17];
                int idCardMod = sum % 11;
                return idCardY[idCardMod].toUpperCase().equals(String.valueOf(idCardLast).toUpperCase());
            }

        }
        return matches;
    }

    /**
     * 从不含校验位的银行卡卡号采用 Luhm 校验算法获得校验位
     * @param nonCheckCodeBankCard 无校验位的银行卡号
     * @return 获取校验位
     */
    private static char getBankCardCheckCode(String nonCheckCodeBankCard){
        if(nonCheckCodeBankCard == null || nonCheckCodeBankCard.trim().length() == 0
                || !nonCheckCodeBankCard.matches("\\d+")) {
            //如果传的不是数据返回N
            return 'N';
        }
        char[] chs = nonCheckCodeBankCard.trim().toCharArray();
        int luhmSum = 0;
        for(int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
            int k = chs[i] - '0';
            if(j % 2 == 0) {
                k *= 2;
                k = k / 10 + k % 10;
            }
            luhmSum += k;
        }
        return (luhmSum % 10 == 0) ? '0' : (char)((10 - luhmSum % 10) + '0');
    }
}
